// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	8/4/2013 4:29:38 PM				
// -----------------------------

#include "LuaTable.h"
#include "Lua.h"
#include "LuaIncl.h"
#include "LuaStackGuard.h"

namespace ObjectLua
{

	LuaTable::LuaTable()
		: LuaObject(nullptr)
		, m_Ref(nullptr)
	{
	}
	LuaTable::LuaTable(Lua* lpLua)
		: LuaObject(lpLua)
		, m_Ref(lpLua)
	{
		lua_newtable(lpLua->getState());
		m_Ref.obtainRef();
	}
	LuaTable::LuaTable(Lua* lpLua, int refIndex)
		: LuaObject(lpLua)
		, m_Ref(lpLua,refIndex)
	{
	}

	LuaTable::LuaTable(const LuaTable& refLuaTable)
		: LuaObject(refLuaTable.getLua())
		, m_Ref(refLuaTable.m_Ref)
	{
	}

	LuaTable& LuaTable::operator=(const LuaTable& refLuaTable)
	{
		m_lpLua = refLuaTable.m_lpLua;
		m_Ref = refLuaTable.m_Ref;
		return (*this);
	}
	
	LuaTable::~LuaTable()
	{
	}

	void LuaTable::addCFunction(const char* name, int (*lpFunc)(lua_State*))
	{
		LUA_ASSERT(name);
		LUA_ASSERT(lpFunc);

		LuaStackGuard stackGuard(m_lpLua);

		m_Ref.push();
		m_lpLua->getStack()->pushString(name);
		m_lpLua->getStack()->pushFunction(lpFunc);
		m_lpLua->getStack()->setTable(-3);
	}

	void LuaTable::addInteger(const char* name, int value)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		m_lpLua->getStack()->pushString(name);
		m_lpLua->getStack()->pushInteger(value);
		lua_settable(m_lpLua->getState(),top);
	}
	void LuaTable::addNumber(const char* name, double value)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		m_lpLua->getStack()->pushString(name);
		m_lpLua->getStack()->pushNumber(value);
		lua_settable(m_lpLua->getState(),top);
	}
	void LuaTable::addBool(const char* name, bool bValue)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		m_lpLua->getStack()->pushString(name);
		m_lpLua->getStack()->pushBool(bValue);
		lua_settable(m_lpLua->getState(),top);
	}
	void LuaTable::addString(const char* name, const char* value)
	{
		LUA_ASSERT(name);
		LUA_ASSERT(value);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		m_lpLua->getStack()->pushString(name);
		m_lpLua->getStack()->pushString(value);
		lua_settable(m_lpLua->getState(),top);
	}
	LuaTable LuaTable::addTable(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		m_lpLua->getStack()->pushString(name);
		LuaTable table(m_lpLua);
		table.m_Ref.push();
		lua_settable(m_lpLua->getState(),top);
		return table;
	}
	LuaTable LuaTable::addMetaTable(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		luaL_newmetatable(m_lpLua->getState(),name);
		LuaTable table(m_lpLua);
		table.m_Ref.obtainRef();
		return table;
	}	
	void LuaTable::setField(const char* name, int idx)
	{
		LUA_ASSERT(name);

		lua_setfield(m_lpLua->getState(),idx,name);
	}


	int LuaTable::getInteger(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		lua_getfield(m_lpLua->getState(),top,name);

		return m_lpLua->getStack()->getInteger(-1);
	}
	double LuaTable::getNumber(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		lua_getfield(m_lpLua->getState(),top,name);

		return m_lpLua->getStack()->getNumber(-1);
	}
	bool LuaTable::getBool(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		lua_getfield(m_lpLua->getState(),top,name);

		return m_lpLua->getStack()->getBool(-1);
	}
	const char* LuaTable::getString(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		lua_getfield(m_lpLua->getState(),top,name);

		return m_lpLua->getStack()->getString(-1);
	}
	LuaTable LuaTable::getTable(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		lua_getfield(m_lpLua->getState(),top,name);

		int refIndex = luaL_ref(m_lpLua->getState(),LUA_REGISTRYINDEX);
		return LuaTable(m_lpLua,refIndex);
	}
	LuaTable LuaTable::getMetaTable(const char* name)
	{
		LUA_ASSERT(name);

		LuaStackGuard stackGuard(m_lpLua);
		m_Ref.push();
		int top = lua_gettop(m_lpLua->getState());
		lua_getfield(m_lpLua->getState(), top, name);
		//luaL_getmetatable(m_lpLua->getState(), name);

		int refIndex = luaL_ref(m_lpLua->getState(),LUA_REGISTRYINDEX);
		return LuaTable(m_lpLua,refIndex);
	}
	void LuaTable::getField(const char* name)
	{
		LUA_ASSERT(name);

		this->push();
		lua_getfield(m_lpLua->getState(), -1, name);
		//m_lpLua->getStack()->pop(-2);
	}
	void LuaTable::push()
	{
		m_Ref.push();
	}

	/*
	//	Register a Table of Functions
	//	To the Table
	*/
	void LuaTable::registerFunctions(const int funcCount, LuaReg functions[])
	{
		m_lpLua->getStack()->registerFunctions(funcCount, functions);
	}
}